home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
pctchnqs
/
1990
/
number5
/
com_pp.asm
< prev
next >
Wrap
Assembly Source File
|
1990-09-02
|
39KB
|
1,069 lines
title COM_PP.ASM
;**************************************************************************
;* COM_PP.ASM is a set of RS232 communications functions. These func-
;* provide basic, interrupt-driven serial communications through an 8052
;* UART. The com_open() and com_set_buffers() functions MUST be called
;* before the com_read() or com_write() functions.
;*
.model small
if @codesize ; large or compact model
bp_ofs equ 6
else ; small or medium model
bp_ofs equ 4
endif
;** Constant Definitions ***************
ERROR equ -1
OK equ 0
;* com port status report bits
PORT_OPEN equ 0001h
RECVD_CHAR equ 0002h
SNDNG_PCKT equ 0004h
HAND_SHAKING equ 0008h
OVERRUN_ERR equ 0010h
PARITY_ERR equ 0020h
FRAMING_ERR equ 0040h
BREAK_ERR equ 0080h
OVERFLOW equ 0100h
INVALID_PORT equ 0200h
PORT_NOT_FND equ 0400h
;* hand-shaking function codes
RECV_TEST equ 1
SEND_TEST equ 2
BUF_EMPTY equ 3
;* line status bits - used to test Line Status Register
OVERRUN equ 02h
PARITY equ 04h
FRAMING equ 08h
BREAK equ 10h
;* interrupt id register bits
DATA_AVAILABLE equ 04h
TRANS_EMPTY equ 02h
;* interrupt enable bits
DATA_AVAIL_INT equ 01h ; Enable data available int
TRANS_EMPTY_INT equ 02h ; Enable transmitter empty int
LINE_STATUS_INT equ 04h ; Enable Line Status Reg int
MODEM_STAT_INT equ 08h ; Enable Modem Status reg int
;* modem control bits
DTR equ 01h
RTS equ 02h
OUT1 equ 04h
OUT2 equ 08h
;* Programmable Interrupt Controller (PIC)
PIC_MASK_REG equ 21h
PIC_EOI equ 20h ; End Of Interrupt
;* com port addresses
COM1 equ 3f8h
COM2 equ 2f8h
;* these are offsets from the base com port address to its various control
;* and status registers
INT_ENABLE equ 01h ; Interrupt Enable Register
INT_ID equ 02h ; Interrupt Identification Reg.
MODEM_CONTROL equ 04h ; Modem Control Register
LINE_STATUS equ 05h ; Line Status Register
MODEM_STATUS equ 06h ; Modem Status Register
;******************************************************************************
.data
public com_status, send_len, send_tail, send_buffer
public recv_len, recv_tail, recv_buffer, old_stack, stack_top
public int_enable_mask
com_status dw 0 ; local status word
com_port dw 0 ; base address of com port
com_int db 0 ; com interrupt vector
PIC_mask db 0 ; Programmable Interrupt
; Controller mask
int_enable_mask db 0 ; this is the uart interrupt
; mask
send_len dw 0 ; size of send buffer
send_tail dw 0 ; send buffer tail
send_buffer dd 0 ; pointer to private send buffer
msg_len dw 0 ; length of send message
recv_len dw 0 ; size of receive buffer
recv_tail dw 0 ; receive buffer tail
recv_buffer dd 0 ; pointer to private receive buffer
old_vector dd 0 ; orginal com interrupt vector
hand_shake dd 0 ; address of handshake function
local_stack dw 100h dup(0)
stack_top dw 0
;******************************************************************************
.code
public _com_open, _com_write, _com_read, _com_close, _com_start_sending
public _com_stop_sending, _com_get_status, _com_clr_recv_buf
public _com_clr_send_buf, _com_set_handshake, _com_set_buffers
public _com_chars_recvd, _com_chars_sent, _com_read_char,
public _com_write_char
old_stack dd 0 ; stack of interrupted routine
save_ax dw 0
;**************************************************************************
;* ASYNC_ISR is the interrupt service routine. It is invoked anytime
;* a byte is received by the UART (8250), or if the 8250 is ready to send
;* another character, or if a line error is detected. The Interrupt
;* Identification Register (INT_ID) is read to determine the interrupt type
;* - Receive, Transmit, or Error - and the appropriate sub-routine is
;* executed. Since the 8250 prioritizes simultaneous interrupts, the INT_ID
;* is checked again prior to exiting to be sure all pending interrupts have
;* been processed.
;*
async_isr proc far
; first save the interrupted routine's stack and substitute our local stack
; old_stack is in the code segment because at this point that's all we can
; count on
mov word ptr cs:old_stack,sp
mov word ptr cs:old_stack + 2,ss
mov save_ax,ax
mov ax,seg com_status
mov ss,ax
mov sp,offset stack_top
sti ; re-enable interrupts
push bp
push bx
push cx
push di
push ds
push dx
push es
push si
mov ax,seg com_status
mov ds,ax
mov dx,com_port ; get base address of com port
add dx,INT_ID ; point to Int. Id. Register
in al,dx
ai1:
; first check for a line status interrupt
cmp al,6 ; check for error interrupt
je ai3
test al,DATA_AVAILABLE ; check for received character
jz ai2 ; if not, make next test
; else
call recv_char ; receive a character
jmp ai_out
ai2:
; check for a transmit hold register empty interrupt
test al,TRANS_EMPTY ; check for transmitter empty
jz ai_out ; if not, leave
; else
call send_char ; send a character
jmp ai_out
ai3:
; it was an error interrupt so identify it
mov dx,com_port ; get port base address
add dx,LINE_STATUS ; point to Line Status Register
in al,dx ; read the register
test al,OVERRUN
jz ai4
or com_status,OVERRUN_ERR
ai4:
test al,PARITY
jz ai5
or com_status,PARITY_ERR
ai5:
test al,FRAMING
jz ai6
or com_status,FRAMING_ERR
ai6:
test al,BREAK
jz ai_out
or com_status,BREAK_ERR
ai_out:
; this is where we check for simultaneous interrupts
mov dx,com_port ; get com port address
add dx,INT_ID ; point to interrupt ident reg
in al,dx ; read register
test al,01h ; check for pending interrupt
jz ai1 ; and if so, process it
; no pending interrupts
mov dx,com_port ; re-set Int. Enable Reg.
add dx,INT_ENABLE
mov al,int_enable_mask
out dx,al
mov al,PIC_EOI ; re-enable the 8259
out 20h,al
pop si
pop es
pop dx
pop ds
pop di
pop cx
pop bx
pop bp
; restore the stack
cli
mov ss,word ptr cs:old_stack + 2
mov sp,word ptr cs:old_stack
mov ax,cs:save_ax
sti
iret
async_isr endp
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;* RECV_CHAR first inputs the character received and then checks
;* for handshaking. If handshaking is enabled then the character
;* received is passed to the hand-shaking routine. The hand-shaking
;* function will clear AH if the byte passed to it should be saved
;* otherwise AH will be non-zero.
;* If byte is to be kept then a test for buffer overflow is made.
;* If the buffer is full an error flag is set and the character is
;* thrown away.
;* Provided the above tests have been passed, the character is
;* saved at the tail of the local receive buffer and a flag is set
;* indicating that there are characters in the receive buffer.
;*
recv_char proc near
mov dx,com_port ; get com port address
in al,dx ; & read character
test com_status,HAND_SHAKING ; check for hand-shaking
jz rc1 ; no hand-shaking so continue
; else
mov ah,RECV_TEST ; set ah to function code
push ax ; (al = character)
if @codesize ; large or compact model
call far ptr [hand_shake]
else ; small or medium model
call word ptr [hand_shake]
endif
add sp,2 ; adjust stack
test ah,0ffh ; see if ah is zero
jz rc1 ; if it is, continue
; else
jmp rc_out ; exit
rc1:
; make sure recv_tail is less than the receive buffer's length
mov dx,recv_tail
cmp dx,recv_len
jl rc2
or word ptr com_status,OVERFLOW
jmp short rc_out
rc2:
; save the byte
push es
les di,recv_buffer ; es:di = receive buffer
add di,recv_tail ; point to current end of buffer
mov es:[di],al ; save character
inc word ptr recv_tail ; increment tail
or com_status,RECVD_CHAR ; and set receive character flag
pop es
rc_out:
ret
recv_char endp
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;* SEND_CHAR first loads the next character to send into AL and then
;* checks to see if hand-shaking is enabled. If so the hand-shaking
;* function is called. The hand-shaking function will clear AH if the byte
;* passed to it should be sent (and send_tail incremented) otherwise AH
;* will be non-zero.
;*
send_char proc near
; first get the next byte in the buffer
push es
les di,send_buffer
add di,send_tail ; point to next character
mov al,es:[di] ; move character into al
pop es
test com_status,HAND_SHAKING ; check protocol
jz sc1
mov ah,SEND_TEST ; set ah to function code
push ax ; al = next send character
if @codesize ; large or compact model
call far ptr [hand_shake]
else ; small or medium model
call word ptr [hand_shake]
endif
add sp,2 ; adjust stack
; if HAND_SHAKE returns with ah > 0 then it has replaced the character in
; al in which case send_tail is not changed, otherwise it is incremented.
; note that since the byte is not re-loaded from the buffer hand_shake
; can substitute another byte and still force send_tail to be incremented.
test ah,0ffh
jnz sc2
sc1:
inc send_tail
sc2: ; loop until Trans Holding Reg
; this test shouldn't be necessary but at least one supposed 8250 clone
; (I don't recall whose) interrupts when the transmit shift register is
; empty and not the transmit hold register
mov ah,al ; save send character in ah
mov dx,com_port ; get port base address
add dx,LINE_STATUS ; point to Line Status Register
sc3:
in al,dx
test al,40h
jz sc3
sub dx,LINE_STATUS ; point back to base address
mov al,ah ; put character back in al
out dx,al ; and send character
mov ax,msg_len ; get message length
cmp ax,send_tail ; & compare to see if
; we're at the end of the message
jne short sc_out
; we've sent the entire message so re-initialize the variables and turn
; off the transmit interrupt
mov word ptr send_tail,0 ; reset send tail
mov word ptr msg_len,0
and com_status,not SNDNG_PCKT ; turn sending flag off
and int_enable_mask,not TRANS_EMPTY_INT ; reset interrupt status
mov dx,com_port ; re-set Int. Enable Reg.
add dx,INT_ENABLE ; point to Interrupt Enable Reg
mov al,int_enable_mask ; clear the transmit bit
out dx,al
sc_out:
ret
send_char endp
;******************************************************************************
;* int com_open(int port,unsinged int params);
;*
;* Only com1 and com2 are supported using IRQ4 and IRQ3 respectively.
;* Once the port has been determined the BIOS (int 14h) is used to set
;* it up. The current interrupt vector is saved for later restoration and
;* ASYNC_ISR is substituted. DTR and RTS are pulled high. The UART's
;* receive buffer is cleared, and interrupts are enabled on the UART and
;* the 8259 Programmable Interrupt Controller (PIC).
;*
;* Returns: -1 if error, otherwise 0.
;*
_com_open proc
push bp
mov bp,sp
push bx
push ds
push dx
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
test com_status,PORT_OPEN ; see if the port is already open
jz co1 ; if not, continue
jmp co_err ; otherwise, return an error
co1:
;* find out which com port - set up first for com2 and then if not
;* modify the settings
mov PIC_mask,08h ; 8259 PIC mask for IRQ3
mov com_int,0bh ; set interrupt to com2
mov bx,0402h ; set si to BIOS com2 address
mov dx,[bp + bp_ofs] ; get com port
cmp dx,1 ; check for com2
je co2 ; and if true test port
; else
mov PIC_mask,10h ; 8259 PIC mask for IRQ4
inc com_int ; reset interrupt to com1
sub bx,2 ; set si to BIOS com1 address
cmp dx,0 ; & check for com1
je co2
or com_status,INVALID_PORT
jmp co_err ; only com1 & com2 are supported
co2:
mov ax,0
push ds
mov ds,ax ; set ds to bios segment
mov ax,[bx] ; get port address from BIOS area
pop ds
cmp ax,0 ; if BIOS address is not 0 then
jne co3 ; initialize port
; else
or com_status,PORT_NOT_FND
jmp co_err ; return an error
co3:
mov com_port,ax ; save com port address
mov ax,[bp + bp_ofs + 2] ; get com parameters
int 14h ; call bios to set com port
;* now we're ready to save the existing com interrupt vector and
;* substitute async_isr for it
push es
mov al,com_int ; vector address
mov ah,35h ; DOS Get Vector function
int 21h ; call DOS
mov word ptr old_vector,bx ; and save the old
mov word ptr old_vector + 2,es ; vector
pop es
mov dx,offset cs:async_isr ; move relative offset of
; interrupt routine to dx
push ds
push cs ; move code segment address
pop ds ; to ds
mov ah,25h ; DOS Set Vector function
int 21h ; call dos
pop ds
;* the only thing left to do is set up the various com port registers
mov dx,com_port ; get port address
mov al,DTR + OUT2 + RTS ; set DTR, Out2, & RTS mask
add dx,MODEM_CONTROL
out dx,al ; set register
sub dx,MODEM_CONTROL ; point back to base
co4:
; loop until the UART's receive buffer is empty
add dx,LINE_STATUS ; point to Line Status Register
in al,dx ; read it
test al,01h ; & check for a waiting char
jz co5 ; if no character continue
; otherwise
sub dx,LINE_STATUS ; point back to base
in al,dx ; read the character
jmp short co4 ; and check it again
co5:
; set the UART to interrupt on received character or line status error
mov int_enable_mask,DATA_AVAIL_INT + LINE_STATUS_INT
mov dx,com_port ; get base address
add dx,INT_ID ; point to Inter. ID Register
in al,dx ; clear it
sub dx,INT_ID
mov al,int_enable_mask
add dx,INT_ENABLE
out dx,al ; enable UART interrupts
or com_status,PORT_OPEN ; set status flag
; now set up the Programable Interrupt Control (PIC) register
cli
in al,PIC_MASK_REG ; read 8259 mask register
mov ah,PIC_mask ; move mask to ah
not ah ; flip the bits
and al,ah ; reset mask for this port
out PIC_MASK_REG,al
sti
mov ax,OK
jmp short co_out
co_err:
mov ax,ERROR ; set zero flag and clear ax
co_out:
pop dx
pop ds
pop bx
pop bp
ret
_com_open endp
;**************************************************************************
;* void com_close(void);
;*
;* com_close() restores the original interrupt vectors, disables the
;* com interrupts, and restores the com registers.
;*
_com_close proc
push bp
mov bp,sp
push ax
push ds
push dx
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
test com_status,PORT_OPEN
jz cc_out
;* restore the 8259 PIC
cli
in al,PIC_MASK_REG
xor al,PIC_mask
out PIC_MASK_REG,al
sti
;* restore the UART registers
mov al,00h ; turn off DTR, RTS, and OUT2
mov dx,com_port
add dx,MODEM_CONTROL
out dx,al ; reset register
sub dx,MODEM_CONTROL ; point back to base
add dx,INT_ENABLE ; and then to Inter. ID Register
out dx,al ; and clear it
;* restore the original com interrupt vector
push ds
lds dx,old_vector
mov al,com_int
mov ah,25h
int 21h
pop ds
mov com_status,0 ; clear the status word
mov recv_tail,0 ; and initialize the buffers
mov send_tail,0
cc_out:
pop dx
pop ds
pop ax
pop bp
ret
_com_close endp
;**************************************************************************
;* int com_write(int length,void *message);
;*
;* This routine is passed the application program's send buffer and the
;* the message length. The buffer address is saved and then the UART is set
;* to interrupt whenever the Transmitter Holding Register is empty.
;*
;* Returns: -1 if error detected or already sending otherwise 0
;*
_com_write proc
push bp
mov bp,sp
push di
push ds
push dx
push es
push si
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
test com_status,PORT_OPEN ; see if port is open
jz cw_err ; if not then return error
; else
test com_status,SNDNG_PCKT ; see if we're already sending
jz cw1 ; if not continue
; else
jmp cw_err ; return error
cw1:
; copy the message into the local send buffer
mov ax,[bp + bp_ofs] ; get message length
mov msg_len,ax ; & save it
mov cx,ax
les di,send_buffer
mov si,[bp + bp_ofs + 2] ; get offset of send buffer
push ds
if @datasize ; large data model
mov ds,[bp + bp_ofs + 4] ; get segment of send buffer
endif
cld
rep movsb ; copy the message
pop ds
; now enable transmit interrupts
cli
or int_enable_mask,TRANS_EMPTY_INT ; set mask
mov dx,com_port ; put port address in dx
add dx,INT_ENABLE ; Interrupt Enable Register
mov al,int_enable_mask
out dx,al ; enable interrupt
or com_status,SNDNG_PCKT ; set the status flag
sti
mov ax,OK
jmp short cw_out
cw_err:
mov ax,ERROR ; set error return
cw_out:
pop si
pop es
pop dx
pop ds
pop di
pop bp
ret
_com_write endp
;*****************************************************************************
;* int com_read(void *recv_buf)
;*
;* This routine is passed the application program's receive buffer.
;* The contents (if any) of the local receive buffer are transferred to it.
;* If hand-shaking is enabled then HAND_SHAKE is called and passed the
;* BUF_EMPTY function code so that it can re-start receving if necessary.
;*
;* Returns: Length of received message or -1 if error.
;*
_com_read proc
push bp
mov bp,sp
push cx
push di
push ds
push es
push si
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
push ds
test com_status,PORT_OPEN ; make sure the port's open
jnz cr1
jmp cr_err
cr1:
mov di,[bp + bp_ofs] ; get offset of program's buffer
if @datasize ; large data model
mov ax,[bp + bp_ofs + 2] ; get segment of program's buffer
mov es,ax ; & put it in es
else ; else
mov ax,ds
mov es,ax
endif
lds si,recv_buffer
mov cx,recv_tail ; set cx to length of string recd
inc cx
cld
rep movsb ; copy the message
; now re-initialize the buffer and flags
pop ds
and com_status,not RECVD_CHAR ; reset status
and com_status,not OVERFLOW
mov cx,recv_tail ; return length of string
mov recv_tail,0
test com_status,HAND_SHAKING ; is hand-shaking is enabled?
jz cr_2 ; if not then exit
; else
mov ah,BUF_EMPTY ; set the function code
push ax
if @codesize ; large or compact model
call far ptr [hand_shake]
else ; small or medium model
call word ptr [hand_shake]
endif
add sp,2 ; adjust stack
cr_2:
mov ax,cx
sti
jmp short cr_out
cr_err:
mov ax,ERROR ; set zero flag and clear ax
cr_out:
pop si
pop es
pop ds
pop di
pop cx
pop bp
ret
_com_read endp
;**************************************************************************
;* int com_read_char(void);
;*
;* Returns the oldest character in the receive buffer. If there are
;* no characters then an error is returned. Note that the return value is
;* an integer. This means that a return value of 0 to 255 is the character
;* received while -1 is an error.
;*
;* Returns: 0 if successful or -1 if error occurs.
;*
_com_read_char proc
push bp
mov bp,sp
push cx
push di
push ds
push es
push si
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
test com_status,PORT_OPEN ; make sure port's open
jnz crc1
jmp crc_err
crc1:
cmp recv_tail,0 ; anything in the buffer?
je crc_err ; no, so exit
mov cx,recv_tail ; set cx for subsequent movsb
push ds
lds si,recv_buffer ; point ds:si to recv buffer
mov al,[si] ; get 1st character in buffer
mov ah,0 ; clear high byte
inc si ; point si to next character
les di,recv_buffer ; es:di = beginning of buffer
cld
rep movsb ; shift remaining characters down
pop ds
dec recv_tail ; adjust tail
cmp recv_tail,0 ; check for empty buffer
jne crc_out ; if not exit
; else
and com_status,not RECVD_CHAR ; reset status
and com_status,not OVERFLOW
crc_err:
mov ax,ERROR ; set error flag and clear ax
crc_out:
pop si
pop es
pop ds
pop di
pop cx
pop bp
ret
_com_read_char endp
;**************************************************************************
;* int com_write_char(char chr);
;*
;* This function sends a character out the com port immediately.
;* If a message is currently being sent an error code is returned.
;*
_com_write_char proc
push bp
mov bp,sp
push cx
push di
push ds
push es
push si
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
test com_status,SNDNG_PCKT ; see if we're sending
jnz cwc_err ; if so, return an error
; else
mov dx,com_port ; get port base address
add dx,LINE_STATUS ; point to Line Status Register
cwc1:
; loop until the transmitter holding register is empty
in al,dx
test al,40h
jz cwc1
sub dx,LINE_STATUS ; point back to base address
mov al,[bp + bp_ofs] ; get character to send
out dx,al ; and send character
mov ax,OK ; indicate no error
jmp short cwc_out ; and exit
cwc_err:
mov ax,ERROR
cwc_out:
pop si
pop es
pop ds
pop di
pop cx
pop bp
ret
_com_write_char endp
;**************************************************************************
;* void com_stop_sending(void);
;*
;* Stop sending disables the the Transmit Buffer Empty interrupt.
;*
_com_stop_sending proc
push ax
push ds
push dx
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
test com_status,SNDNG_PCKT ; are we in send mode?
jz css1_out ; no, so just return
cli ; make sure we're not interrupted
and int_enable_mask,not TRANS_EMPTY_INT ; reset interrupt status
mov dx,com_port ; re-set Int. Enable Reg.
add dx,INT_ENABLE
mov al,int_enable_mask ; disable interrupt
out dx,al
sti
css1_out:
pop dx
pop ds
pop ax
ret
_com_stop_sending endp
;**************************************************************************
;* void com_start_sending(void);
;*
;* Start sending is the complement to stop sending. It checks to see
;* if the SNDNG_PCKT flag is true and if so re-enables the transmit
;* interrupt. Ohterwise it simply returns.
;*
_com_start_sending proc
push bp
mov bp,sp
push ax
push ds
push dx
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
test com_status,SNDNG_PCKT ; are we in send mode?
jz css2_out ; no, so just return
cli ; make sure we're not interrupted
or int_enable_mask,TRANS_EMPTY_INT ; set status to send interrupts
mov dx,com_port ; put port address in dx
add dx,INT_ENABLE ; Interrupt Enable Register
mov al,int_enable_mask
out dx,al ; enable register
sti
css2_out:
pop dx
pop ds
pop ax
pop bp
ret
_com_start_sending endp
;**************************************************************************
;* unsigned int com_get_status(void);
;*
;* This function returns a copy of the com_status word maintained
;* by this module. The status word consists of a sset of bit flags. See
;* SERIAL.HPP for the bit structure that defines them.
;*
_com_get_status proc
push ds
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
mov ax,com_status
pop ds
ret
_com_get_status endp
;**************************************************************************
;* int com_chars_recvd(void);
;*
;* Returns the number of characters currently in the receive buffer.
;*
_com_chars_recvd proc
push ds
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
mov ax,recv_tail
pop ds
ret
_com_chars_recvd endp
;**************************************************************************
;* int com_chars_sent
;*
;* Returns the number of characters that have been sent.
;*
_com_chars_sent proc
push ds
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
mov ax,send_tail
pop ds
ret
_com_chars_sent endp
;**************************************************************************
;* void com_set_buffers(void *recv_buffer, void *send_buffer, int len);
;*
;* Sets the local send and receive buffers to be used by this module.
;*
_com_set_buffers proc
push bp
mov bp,sp
push ax
push ds
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
mov ax,[bp + bp_ofs] ; receive buffer offset
mov word ptr recv_buffer,ax
mov ax,[bp + bp_ofs + 2] ; receive buffer segment
mov word ptr recv_buffer + 2,ax
mov ax,[bp + bp_ofs + 4] ; send buffer offset
mov word ptr send_buffer,ax
mov ax,[bp + bp_ofs + 6] ; send buffer segment
mov word ptr send_buffer + 2,ax
mov ax,[bp + bp_ofs + 8] ; buffer length
else
mov ax,[bp + bp_ofs] ; receive buffer offset
mov word ptr recv_buffer,ax
mov word ptr recv_buffer + 2,ds
mov ax,[bp + bp_ofs + 2] ; send buffer offset
mov word ptr send_buffer,ax
mov word ptr send_buffer + 2,ds
mov ax,[bp + bp_ofs + 4] ; send buffer length
endif
mov send_len,ax
mov recv_len,ax
pop ds
pop ax
pop bp
ret
_com_set_buffers endp
;**************************************************************************
;* void com_clr_recv_buf(void);
;*
;* Effectively clears all characters from the receive buffer by
;* resetting recv_tail to 0.
;*
_com_clr_recv_buf proc
push ds
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
cli
mov recv_tail,0
sti
pop ds
_com_clr_recv_buf endp
;**************************************************************************
;* void com_clr_recv_buf(void);
;*
;* Effectively clears all characters from the send buffer by
;* resetting send_tail and msg_len to 0. Note: if we're currently
;* sending then sending is stopped.
;*
_com_clr_send_buf proc
push ds
if @datasize ; large data model
mov ax,seg com_status
mov ds,ax
endif
test com_status,SNDNG_PCKT ; are we sending now?
jz ccsb1 ; no, continue
; else
call _com_stop_sending ; stop sending
ccsb1:
cli ; avoid interruptions
and com_status,not SNDNG_PCKT
mov word ptr send_tail,0
mov word ptr msg_len,0
sti
pop ds
_com_clr_send_buf endp
;**************************************************************************
;* void _com_set_handshake(HANDSHAKE hs);
;*
;* Sets a pointer to the hand-shaking routine and sets the status
;* flag indicating that hand-shaking is enabled. If the pointer passed
;* to this routine is NULL then hand-shaking is disabled.
;*
_com_set_handshake proc near
push bp
mov bp,sp
push ax
push bx
push ds
if @datasize ; large data model
mov ax,seg com_status ; change to local data segment
mov ds,ax ; if necessary
endif
mov ax,[bp + bp_ofs] ; get offset address of hand-
; shaking function
mov word ptr hand_shake,ax ; save it
if @codesize ; large or compact model
mov bx,[bp + bp_ofs + 2] ; get segment address
or ax,bx ; see if we were passed a NULL
jz csh1 ; if so, disable hand-shaking
; else
mov word ptr hand_shake + 2,bx ; save the segment
or com_status,HAND_SHAKING ; set the enable flag
jmp short csh_out
else ; small or medium model
test ax,0ffffh ; were we passed a NULL?
jz csh1 ; yes, so disable hand-shaking
; else
mov word ptr hand_shake + 2,cs ; set hand-shake segment to cs
or com_status,HAND_SHAKING ; set the enable flag
jmp short csh_out
endif
csh1:
mov word ptr hand_shake + 2,0
and com_status,not HAND_SHAKING ; disable hand-shaking
csh_out:
pop ds
pop bx
pop ax
pop bp
ret
_com_set_handshake endp
end